package x.ovo.wechat.bot.plugin;

import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONUtil;
import picocli.CommandLine;
import x.ovo.wechat.bot.core.Constant;
import x.ovo.wechat.bot.core.Context;
import x.ovo.wechat.bot.core.command.CommandExcutor;
import x.ovo.wechat.bot.core.plugin.Plugin;
import x.ovo.wechat.bot.core.plugin.PluginDescription;
import x.ovo.wechat.bot.core.plugin.PluginManager;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Callable;


/**
 * 插件管理命令执行器
 *
 * @author ovo on 2024/07/24.
 */
@CommandLine.Command(name = "plugin-manager", aliases = "pm", description = "插件管理命令执行器")
public class PmExecutor extends CommandExcutor implements Callable<String> {

    @CommandLine.Parameters(paramLabel = "operator", index = "0", description = "操作方式 [enable|disable|load|unload|reload|list|info]")
    private String operator;

    @CommandLine.Parameters(paramLabel = "plugins", index = "1..*", description = "需要操作的插件名称")
    private String[] plugins;

    private PluginManager pm;

    public PmExecutor(Plugin plugin) {
        super(plugin);
        pm = Optional.ofNullable(this.ctx.getPluginManager()).orElse(Context.INSTANCE.getPluginManager());
    }

    @Override
    public String call() throws Exception {
        String from = this.message.isGroup() ? this.message.getFrom().getNickName() : "";
        return switch (operator) {
            case "enable" -> this.enable(from);
            case "disable" -> this.disable(from);
            case "load" -> this.load();
            case "unload" -> this.unload();
            case "reload" -> this.reload();
            case "list" -> this.list(from);
            case "info" -> this.info();
            default -> this.spec.commandLine().getUsageMessage();
        };
    }

    private String enable(String from) {
        List<String> error = new ArrayList<>();
        List<String> success = new ArrayList<>();
        Arrays.stream(plugins)
                .distinct()
                .forEach(name -> {
                    if (this.pm.get(name) == null) {
                        error.add(name);
                    } else {
                        this.pm.enable(name, from);
                        this.pm.saveLimitConfig();
                        success.add(name);
                    }
                });
        return (Objects.equals(from, "") ? "本群" : "") +
                (success.isEmpty() ? "" : "插件 " + success + " 已成功启用，") +
                (error.isEmpty() ? "" : "插件 " + error + " 不存在");
    }

    private String disable(String from) {
        List<String> error = new ArrayList<>(), success = new ArrayList<>();
        Arrays.stream(plugins)
                .distinct()
                .forEach(name -> {
                    if (this.pm.get(name) == null) {
                        error.add(name);
                    } else {
                        this.pm.disable(name, from);
                        this.pm.saveLimitConfig();
                        success.add(name);
                    }
                });
        return (Objects.equals(from, "") ? "" : "本群") +
                (success.isEmpty() ? "" : "插件 " + success + " 已成功禁用") +
                (error.isEmpty() ? "" : "，插件 " + error + " 不存在");
    }

    private String load() {
        List<String> error = new ArrayList<>(), success = new ArrayList<>();
        Arrays.stream(this.plugins).forEach(name -> {
            try {
                this.pm.load(name);
                success.add(name);
            } catch (Exception e) {
                error.add(StrUtil.format("插件 [{}] 加载失败：{}", name, e.getMessage()));
            }
        });

        String successStr = CollUtil.isEmpty(success) ? "" : StrUtil.format("插件 {} 已成功加载", success);
        String errorStr = CollUtil.isEmpty(error) ? "" : String.join("\n", error);
        return StrUtil.join("\n", successStr, errorStr);
    }

    private String unload() {
        List<String> error = new ArrayList<>(), success = new ArrayList<>();
        Arrays.stream(this.plugins).forEach(name -> {
            try {
                this.pm.unload(name);
                success.add(name);
            } catch (Exception e) {
                error.add(StrUtil.format("插件 [{}] 卸载失败：{}", name, e.getMessage()));
            }
        });
        String successStr = CollUtil.isEmpty(success) ? "" : StrUtil.format("插件 {} 已成功卸载", success);
        String errorStr = CollUtil.isEmpty(error) ? "" : String.join("\n", error);
        return StrUtil.join("\n", successStr, errorStr);
    }

    private String reload() {
        Arrays.stream(this.plugins).forEach(name -> {
            this.pm.unload(name);
            this.pm.load(name);
        });
        return "插件 " + Arrays.toString(this.plugins) + " 已成功重载";
    }

    private String list(String from) {
        Collection<String> plugins = this.pm.list().stream().map(plugin -> (plugin.isEnabled() ? "✔️ " : "❌ ") + plugin.getPluginDesc().getName()).toList();
        Collection<String> groups = this.pm.list(from).stream().map(plugin -> plugin.getPluginDesc().getName()).toList();
        JSON json = JSONUtil.readJSON(Constant.Files.GROUP_PLUGIN_FILE, StandardCharsets.UTF_8);
        String mode = JSONUtil.parseObj(json).getStr("mode");
        String string = StrUtil.format("插件列表 [共 {} 个]，限制模式: {}", plugins.size(), mode) + Constant.delimiter + String.join("\n", plugins);
        if (CollUtil.isNotEmpty(groups)) {
            String status = mode.equals("white-list") ? "启用" : "禁用";
            string += Constant.delimiter + "本群已" + status + "插件：\n" + String.join(", ", groups);
        }
        return string;
    }

    private String info() {
        String name = this.plugins[0];
        Plugin plugin = this.pm.get(name);
        if (Objects.isNull(plugin)) return "插件 [" + name + "] 不存在";

        PluginDescription desc = plugin.getPluginDesc();
        StringBuilder sb = new StringBuilder();
        sb.append("插件名称：").append(desc.getName()).append("\n");
        sb.append("插件版本：").append(desc.getVersion()).append("\n");
        sb.append("插件作者：").append(String.join(",", desc.getAuthors())).append("\n");
        sb.append("插件主类：").append(desc.getMain()).append("\n");
        sb.append("插件描述：").append(desc.getDescription()).append("\n");
        CommandExcutor excutor = plugin.getCommandExcutor();
        if (Objects.nonNull(excutor)) {
            List<String> list = new ArrayList<>();
            CommandLine.Model.CommandSpec spec = new CommandLine(excutor).getCommandSpec();
            String command = spec.name();
            String[] aliases = spec.aliases();
            list.add(command);
            list.addAll(Arrays.asList(aliases));
            sb.append("插件指令：").append(String.join(",", String.join(", ", list))).append("\n");
        }
        return "插件 [" + name + "] 信息" + Constant.delimiter + sb;
    }

}
